#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<sys/epoll.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/wait.h>
#include "private_type.h"
#include "private_log.h"
#include "proxy_type.h"
#include <netinet/tcp.h>

int SOCKET_CreateEpoll()
{
    UINT uiEpoolFd = 0;
    uiEpoolFd = epoll_create(PROXY_EPOLL_MAX);
    return uiEpoolFd;
}


int SOCKET_AddEpoll(UINT32 uiEpollFd, UINT32 uiSocketFd, UINT32 uiflags)
{
    struct epoll_event stEv;
    memset(&stEv, 0, sizeof(struct epoll_event));
    stEv.data.fd = uiSocketFd;
    stEv.events = uiflags;
    return epoll_ctl(uiEpollFd, EPOLL_CTL_ADD, uiSocketFd, &stEv);
}
int SOCKET_ModifyEpoll(UINT32 uiEpollFd, UINT32 uiSocketFd, UINT32 uiflags)
{
    struct epoll_event stEv;
    memset(&stEv, 0, sizeof(struct epoll_event));
    stEv.data.fd = uiSocketFd;
    stEv.events = uiflags;
    return epoll_ctl(uiEpollFd, EPOLL_CTL_MOD, uiSocketFd, &stEv);
}
int SOCKET_DelEpoll(UINT32 uiEpollFd, UINT32 uiSocketFd, EPOOL_LOOP_CLOSE f_FuncClose)
{
    if(NULL != f_FuncClose)
        f_FuncClose(uiEpollFd, uiSocketFd);
    close(uiSocketFd);
    return epoll_ctl(uiEpollFd, EPOLL_CTL_DEL, uiSocketFd, NULL);
}

int SOCKET_EpollLoop
(
    int uiEpollFd,
    EPOOL_LOOP_READ f_FuncRead,
    EPOOL_LOOP_WRITE f_FuncWrite,
    EPOOL_LOOP_CLOSE f_FuncClose
)
{
    struct epoll_event stEvents[PROXY_EPOLL_MAX];
    int i = 0;
    int iWaitTime = 0;
	static int iTimeoutOut = 0;

    iWaitTime = iTimeoutOut - sys_GetTimeMsecs();

    if((iWaitTime <= 0) || (iWaitTime > PROXY_EPOLL_TIMEOUT))
    {
        iTimeoutOut = sys_GetTimeMsecs() + PROXY_EPOLL_TIMEOUT;
        timer_scheduler();
        return TRUE;
    }

    int uiFds = epoll_wait(uiEpollFd, stEvents, PROXY_EPOLL_MAX, iWaitTime);
    if (uiFds == 0)
    {
        iTimeoutOut = sys_GetTimeMsecs() + PROXY_EPOLL_TIMEOUT;
        timer_scheduler();

        return TRUE;
    }

    for(i = 0; i<uiFds;i++)
    {

        if ((stEvents[i].events & EPOLLIN) || (stEvents[i].events & EPOLLPRI))
        {
            if(NULL != f_FuncRead)
                f_FuncRead(uiEpollFd, stEvents[i].data.fd);
        }
        if (stEvents[i].events & EPOLLOUT)
        {
            if(NULL != f_FuncWrite)
                f_FuncWrite(uiEpollFd, stEvents[i].data.fd);
        }
        if ( (stEvents[i].events & EPOLLRDHUP) || (stEvents[i].events & EPOLLERR) || (stEvents[i].events & EPOLLHUP))
        {
            SOCKET_DelEpoll(uiEpollFd, stEvents[i].data.fd, f_FuncClose);
        }
    }

    return TRUE;
}

#if 0
#endif
int SOCKET_TcpServerCreate(UINT uiSip, UINT16 usPort)
{
    int fd = 0;
    struct sockaddr_in stSocketAddr;
    if((fd = socket(AF_INET, SOCK_STREAM, 0))==-1)
    {
         CW_SendErr("socket error");
         return -1;
    }

    stSocketAddr.sin_family=AF_INET;
    stSocketAddr.sin_port=htons(usPort);
    stSocketAddr.sin_addr.s_addr=htonl(uiSip);
    bzero(&(stSocketAddr.sin_zero),8);
    if(bind(fd,(struct sockaddr *)&stSocketAddr,sizeof(struct sockaddr))==-1)
    {
        CW_SendErr("bind error");
        return -1;
    }
    if(listen(fd,PROXY_EPOLL_MAX)==-1)
    {
        CW_SendErr("listen error");
        return -1;
    }
    CW_SendErr("Bind server: %s:%d \n", inet_ntoa(stSocketAddr.sin_addr),stSocketAddr.sin_port);

    return fd;
}

int SOCKET_TcpClientConnect(UINT uiDip, UINT16 usPort)
{
    int fd = 0;
    int ret = 0;
    struct sockaddr_in stSocketAddr;

    fd = socket(AF_INET, SOCK_STREAM, 0);

    stSocketAddr.sin_family=AF_INET;
    stSocketAddr.sin_port=htons(usPort);
    stSocketAddr.sin_addr.s_addr=(uiDip);

    ret = connect(fd, (struct sockaddr *)&stSocketAddr, sizeof(stSocketAddr));
	if(ret < 0) {
		CW_SendErr("Fail to connect server: %s:%d , %d\n", inet_ntoa(stSocketAddr.sin_addr),stSocketAddr.sin_port, ret);
		return -1;
	}

    return fd;
}

